/*
 * Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <QColorDialog>
#include <QMessageBox>
#include "Parametric3DForm.h"
#include "ui_Parametric3DForm.h"

#include "Parameter.h"
#include "Expression3D.h"
#include "ParametricObject3D.h"
#include "Project.h"

#include "FixedParameterDelegate.h"
#include "AutoParameterDelegate.h"

#include "FixedParametersModel.h"
#include "AutoParametersModel.h"

#include "Expression3DDialog.h"
#include "GetExpression3DDialog.h"

Parametric3DForm::Parametric3DForm(QWidget *parent) :
    QWidget(parent),
    m_ui(new Ui::Parametric3DForm)
{
    _object = 0;
    _project = 0;
    _modified = false;
    m_ui->setupUi(this);
    _fixedParametersModel = new FixedParametersModel(this);
    _fixedParametersModel->setList(&_fixedParameters);
    _autoParametersModel = new AutoParametersModel(this);
    _autoParametersModel->setList(&_autoParameters);

    m_ui->autoTableView->setShowGrid(false);
    m_ui->fixedTableView->setShowGrid(false);
    m_ui->autoTableView->setModel(_autoParametersModel);
    m_ui->fixedTableView->setModel(_fixedParametersModel);
    m_ui->autoTableView->setItemDelegate(new AutoParameterDelegate(0,1,2));
    m_ui->fixedTableView->setItemDelegate(new FixedParameterDelegate(0,1));

    connect(m_ui->nameEdit,SIGNAL(textEdited(QString)),this,SLOT(onNameChanged(QString)));
    connect(m_ui->colorButton,SIGNAL(clicked()),this,SLOT(onColorButtonClicked()));
    connect(m_ui->newExpressionButton,SIGNAL(clicked()),this,SLOT(onNewExpressionButtonClicked()));
    connect(m_ui->getExpressionButton,SIGNAL(clicked()),this,SLOT(onGetExpressionButtonClicked()));
    connect(m_ui->goAutoButton,SIGNAL(clicked()),this,SLOT(onGoAutoClicked()));
    connect(m_ui->goFixedButton,SIGNAL(clicked()),this,SLOT(onGoFixedClicked()));
}

Parametric3DForm::~Parametric3DForm()
{
    delete m_ui;
}

void Parametric3DForm::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        m_ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void Parametric3DForm::setObject(ParametricObject3D * object){
    if(_modified){
        QMessageBox msg;
        msg.setText(tr("The setting for the current object have been changed..."));
        msg.setInformativeText(tr("Do you want to apply changes?"));
        msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msg.setDefaultButton(QMessageBox::Yes);
        int ret = msg.exec();
        switch (ret) {
            case QMessageBox::Yes:
            apply();
            break;
            case QMessageBox::No:
            break;
            default:
            break;
        }
    }
    _object = object;
    _project = 0;
    _expression  = 0;
    _parametersChanged = false;
    cleanUpParams();
    if(_object){
        _project = qobject_cast<Project*>(_object->parent());
        if(_object->type()==Object::Curve)
            m_ui->mainGroupBox->setTitle(tr("Curve"));
        else if(_object->type()==Object::Surface)
            m_ui->mainGroupBox->setTitle(tr("Surface"));
    }
    init();
}

void Parametric3DForm::init(){
    if(_object){
        _objectName = _object->objectName();
        _expression = _object->expression();
        _color = _object->color();
        m_ui->nameEdit->setText(_objectName);
        QPixmap pixmap(70,70);
        pixmap.fill(_color);
        QIcon icon(pixmap);
        m_ui->colorButton->setIcon(icon);
        if(_object->expression())
            m_ui->getExpressionButton->setText(_object->expression()->objectName());
        else
            m_ui->getExpressionButton->setText(tr("Select..."));
        initParamsFromObject();
        _parametersChanged = false;
        _modified = false;
    }
}

void Parametric3DForm::apply(){
    if(_object){
        if(_objectName!=_object->objectName())
            _object->setObjectName(_objectName);
        //if(_object->color()!=_color)
            _object->setColor(_color);
        if(_object->expression()!=_expression){
            _object->setExpression(_expression);
        }
        if(_parametersChanged){
            QList<Parameter*>::iterator p;
            for(p=_autoParameters.begin();p!=_autoParameters.end();++p)
                _object->updateParameter((*p));
            for(p=_fixedParameters.begin();p!=_fixedParameters.end();++p)
                _object->updateParameter((*p));
            _parametersChanged = false;
        }
        _modified = false;
        emit modified(_modified);
    }
}

void Parametric3DForm::revert(){
    if(_object){
        init();
        _modified = false;
        emit modified(false);
    }
}
ParametricObject3D* Parametric3DForm::object(){
    return _object;
}
void Parametric3DForm::onNameChanged(const QString& name){
    if(_object){
        _objectName = name;
        _modified = true;
        emit modified(true);
    }
}

void Parametric3DForm::onParametersChanged(){
    if(_object){
        _parametersChanged = true;
        _modified = true;
        emit modified(true);
    }
}

void Parametric3DForm::onColorButtonClicked() {
    if(_object){
        QColor new_color = QColorDialog::getColor(_color,this);
        if(new_color!=_color){
            _color = new_color;
            QPixmap pixmap(70,70);
            pixmap.fill(_color);
            QIcon icon(pixmap);
            m_ui->colorButton->setIcon(icon);
            _modified = true;
            emit modified(true);
        }
    }
}

void Parametric3DForm::onNewExpressionButtonClicked() {
    if(_object){
        Expression3D* expr = new Expression3D();
        Expression3DDialog dlg(expr);
        int result = dlg.exec();
        switch(result){
            case QDialog::Accepted:
                _project->addExpression(expr);
                m_ui->getExpressionButton->setText(expr->objectName());
                initParamsFromExpression();
                _parametersChanged = true;
                break;
            case QDialog::Rejected:
                delete expr;
                break;
            default:
                break;
        }
    }
}

void Parametric3DForm::onGetExpressionButtonClicked(){
    if(_object){
        GetExpression3DDialog dlg(_project,this);
        int result = dlg.exec();
        switch(result){
            case QDialog::Accepted:
                _expression = dlg.expression();
                m_ui->getExpressionButton->setText(_expression->objectName());
                initParamsFromExpression();
                _parametersChanged = true;
                break;
            case QDialog::Rejected:
                break;
            default:
                break;
        }
        _modified = true;
        emit modified(true);
    }
}

void Parametric3DForm::onGoAutoClicked(){
    if(_object){
        int idx = m_ui->fixedTableView->currentIndex().row();
        if(idx>=0){
            Parameter *p = _fixedParameters.at(idx);
            _fixedParameters.removeAt(idx);
            p->setAuto(true);
            _autoParameters.append(p);
            _autoParametersModel->update();
            _fixedParametersModel->update();
            _modified = true;
            emit modified(true);
        }
    }
}

void Parametric3DForm::onGoFixedClicked(){
    if(_object){
        int idx = m_ui->autoTableView->currentIndex().row();
        if(idx>=0){
            Parameter *p = _autoParameters.at(idx);
            _autoParameters.removeAt(idx);
            p->setFixed(true);
            _fixedParameters.append(p);
            _autoParametersModel->update();
            _fixedParametersModel->update();
            _modified = true;
            emit modified(true);
        }
    }

}

void Parametric3DForm::cleanUpParams(){
    QList<Parameter*>::iterator p;
    for(p=_autoParameters.begin();p!=_autoParameters.end();++p){
        delete (*p);
    }
    for(p=_fixedParameters.begin();p!=_fixedParameters.end();++p){
        delete (*p);
    }
    _autoParameters.clear();
    _fixedParameters.clear();
}


void Parametric3DForm::initParamsFromObject(){
    cleanUpParams();
    if(_object){
        QList<Parameter*>::iterator p;
        for(p=_object->parameters().begin();p!=_object->parameters().end();++p){
            Parameter *param = qobject_cast<Parameter*>((*p)->clone());
            param->setParent(this);
            if(param->isAuto())
                _autoParameters.push_back(param);
            else
                _fixedParameters.push_back(param);
            connect(param,SIGNAL(changed()),this,SLOT(onParametersChanged()));
        }
        _autoParametersModel->update();
        _fixedParametersModel->update();
    }
}

void Parametric3DForm::initParamsFromExpression(){
    cleanUpParams();
    if(_expression){
        for(int i = 0; i < _expression->variablesList().count(); ++i)
        {
            Parameter* param = new Parameter(_expression->variablesList()[i]);
            param->setParent(this);
            connect(param,SIGNAL(changed()),this,SLOT(onParametersChanged()));
            _autoParameters.append(param);
        }
    }
    _autoParametersModel->update();
    _fixedParametersModel->update();
}
